/*
 * Copyright (c) 2022 Hong Jiahua
 * https://gitee.com/arrco/jh_stack
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
/**
  * @file        jh_stack.c
  * @brief       栈
  * @details     栈
  * @author      Hong Jiahua
  * @version     1.1.0
  * @date        2022-02-20
  * @copyright   2022 Hong Jiahua MIT License
  */
#include "jh_stack.h"

/************************************************************************/
/*                                                                      */
/************************************************************************/
/**
  * @brief      判断栈是否为空
  * @param[in]  stack   栈
  *
  * @return     errcode
  * @retval      1      栈为空
  * @retval      0      栈不为空
  * @retval     -1      失败
  */
int jh_stack_is_empty(jh_stack_t* stack) {
    if(stack == NULL)
        return -1;
    
    return stack->data_len == 0;
}

/**
  * @brief      判断栈是否已满
  * @param[in]  stack   栈
  *
  * @return     errcode
  * @retval      1      栈已满
  * @retval      0      栈未满
  * @retval     -1      失败
  */
int jh_stack_is_full(jh_stack_t* stack) {
    if(stack == NULL)
        return -1;
    
    return stack->data_len == stack->num;
}

/**
  * @brief      获取栈的数据数量
  * @param[in]  stack   栈
  *
  * @return     errcode
  * @retval     >=0     栈的数据数量
  */
size_t jh_stack_count(jh_stack_t* stack) {
    if(stack == NULL)
        return 0;
    
    return stack->data_len;
}

/**
  * @brief      入栈
  * @param[in]  stack   栈
  * @param[in]  item    要入栈的数据项
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      失败
  */
int jh_stack_push(jh_stack_t* stack, void* item) {
    if(stack == NULL || item == NULL || stack->data_len >= stack->num)
        return -1;

    memcpy(stack->base + stack->data_len * stack->size, item, stack->size);
    stack->data_len ++;
    
    return 0;
}

/**
  * @brief      出栈
  * @param[in]  stack   栈
  * @param[in]  item    要出栈的数据项
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      失败
  */
int jh_stack_pop(jh_stack_t* stack, void* item) {
    if(stack == NULL || item == NULL || stack->data_len == 0)
        return -1;
    
    stack->data_len --;
    memcpy(item, stack->base + stack->data_len * stack->size, stack->size);
    
    return 0;
}

/**
  * @brief      查看栈顶的数据
  * @param[in]  stack   栈
  * @param[in]  item    栈顶的数据项
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      失败
  */
int jh_stack_peek(jh_stack_t* stack, void* item) {
    if(stack == NULL || item == NULL || stack->data_len == 0)
        return -1;
    
    memcpy(item, stack->base + (stack->data_len - 1) * stack->size, stack->size);
    
    return 0;
}

/**
  * @brief      查看栈底的数据
  * @param[in]  stack   栈
  * @param[in]  item    栈底的数据项
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      失败
  */
int jh_stack_peek_bottom(jh_stack_t* stack, void* item) {
    if(stack == NULL || item == NULL || stack->data_len == 0)
        return -1;
    
    memcpy(item, stack->base, stack->size);
    
    return 0;
}

/**
  * @brief      清空栈
  * @param[in]  stack   栈
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      失败
  */
int jh_stack_clear(jh_stack_t* stack) {
    if(stack == NULL)
        return -1;
    
    return stack->data_len = 0;
}

/**
  * @brief      栈数据排序
  * @param[in]  stack   栈
  * @param[in]  compare 指向用于比较两个数据项的函数指针
  *
  * @return     errcode
  * @retval     0       成功
  * @retval     -1      失败
  */
int jh_stack_sort(jh_stack_t* stack, int (*compare)(const void*, const void*)) {
    if(stack == NULL || compare == NULL)
        return -1;
    
    qsort(stack->base, stack->data_len, stack->size, compare);
    
    return 0;
}

/**
  * @brief      栈初始化
  * @param[in]  stack   栈
  * @param[in]  base    指向用于栈的数组
  * @param[in]  num     数组中能存放的数据项数量
  * @param[in]  size    数组中每个数据项的大小
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      失败
  */
int jh_stack_init(jh_stack_t* stack, void* base, size_t num, size_t size) {
    if(stack == NULL || base == NULL)
        return -1;
    
    stack->base = base;
    stack->num = num;
    stack->size = size;
    stack->data_len = 0;
    
    return 0;
}

#ifdef JH_STACK_DYNAMIC_SPACE
/**
  * @brief      栈空间申请
  * @param[in]  stack   栈
  * @param[in]  num     数组中能存放的数据项数量
  * @param[in]  size    数组中每个数据项的大小
  *
  * @return     errcode
  * @retval      0      成功
  * @retval     -1      失败
  */
int jh_stack_space_malloc(jh_stack_t* stack, size_t num, size_t size) {
    if(stack == NULL)
        return -1;
    
    stack->base = JH_STACK_MALLOC(num * size);
    stack->num = num;
    stack->size = size;
    stack->data_len = 0;
    
    return 0;
}

/**
  * @brief      栈空间释放
  * @param[in]  stack       栈
  *
  * @return     errcode
  * @retval      0          成功
  * @retval     -1          失败
  */
int jh_stack_space_free(jh_stack_t* stack) {
    if(stack == NULL || stack->base == NULL)
        return -1;
    
    JH_STACK_FREE(stack->base);
    
    return 0;
}
#endif
